<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <title>reStructuredText editor</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" >

    <script type="text/javascript" src="../static/comet.js"></script>
    <script type="text/javascript" charset="utf-8">
       //document.domain = extract_xss_domain(document.domain);
    </script>

    <script type="text/javascript" src="../static/json2.js"></script>
    <script type="text/javascript" src="../static/getset.js"></script>
    <script type="text/javascript" src="../static/utils.js"></script>
    <script type="text/javascript" src="../static/jquery-1.3.1.min.js"></script>
    <script type="text/javascript" src="../static/diff_match_patch.js"></script>

    <style type="text/css">
        a:link { color: #0000cc; }
        body { background: #fff; margin: 3px 8px;}
        body, select, input { font-family: arial, sans-serif;}
        body { font-size: 83%;}
        body, html{height:100%;}
        body {
/*              font-size: 83%; */
            font-family: arial, sans-serif;
            border-collapse: separate;
        }
        #cell{
            height:100%;
            width: 100%;
        }
        #contentbox {
            padding-left: 1px;
            font-size: 9pt; 
            padding-right: 1px;
            width: 610px; /* 610px for firefox */
            height: 560px;
            font-family: monospace;
        }
        .divcontentbox {
        }
        #outputdiv{
        }
        #outputbox{
            width:  100%;
            height: 560px;
            border: 1px dashed black;
        }
        .round4, .round2, .round1{
            font-size: 0;
            height: 1px;
            margin: 0;
            padding: 0;
        }
        .round1{
            border-left: 1px solid white;
            border-right: 1px solid white;
        }
        .round2{
            border-left: 2px solid white;
            border-right: 2px solid white;
        }
        .round4{
            border-left: 4px solid white;
            border-right: 4px solid white;
        }
        .helpcontent, .headercontent{
            font-size: 90%;
            padding: 6px;
            margin: 0;
        }
        .helpcontent>b {font-size: 105%;}
        .help, .header{
            margin: 5px;
        }
        .header {
            background: #333333;
            color: white;
        }
        .help{
            background: #DDDDDD;
        }
        #documentbox{width:100%; float:left;}
        #documentbox>h1{margin:0px;padding:0px;}
        .bar{float:right;width:30em;}
        .bar>div{float:left; margin-right:2px;}
        [contenteditable=true] {border: 1px solid #333333}
        [contenteditable=true]:hover {border: 1px dotted grey}
        #username {width:100px; float:left;}
        .lbar{float:left; width:40em; font-weight:bolder; color: #CC9999;}
        .vbar{float:left;}
        .vbar>div{float:left;}
  </style>

    <script type="text/javascript">
    </script>
</head>
<body>

<div class="header">
    <div class="round4"></div>
    <div class="round2"></div>
    <div class="round1"></div>
    <div class="headercontent">
        <div class="bar"><div>Username: </div><div id="username" contenteditable="true"  >{{name}}</div><div style="margin-left:10px;">Latency:</div><div id="latency">??</div></div>
        <div id="documentbox"><h1 id="documentname">Real time ReStructuredText editor - share this url!</h1></div><br style="clear:both">
        <div class="bar"><div>Editors: </div><div id="users"></div></div>
        <div class="lbar"><div></div><div id="infobox">&nbsp;</div></div>
        <div class="vbar"><div>Version: </div><div id="versionbox">{{contentversion}}</div></div>
        <br style="clear:both">
    </div>
    <div class="round1"></div>
    <div class="round2"></div>
    <div class="round4"></div>
</div>
    
    <table cellspacing="2" cellpadding="2" border="0"><tbody><tr>
    <td>
        <div class="divcontentbox">
            <textarea id="contentbox" wrap="soft" cols="85">{{contentbox}}</textarea>
        <div>
    </td>
    <td id="cell">
        <div id="outputdiv">
            <iframe id="outputbox" src="./output/"></iframe>
        </div>
    </td>
    </tr><tr>
    <td valign="top">
        <!--
        Snippet stolen from Google code.google.com
        -->
        <div class="help" style="float:left;">
            <div class="round4"></div>
            <div class="round2"></div>
            <div class="round1"></div>
            <div class="helpcontent">
                <b>reStructuredText help</b><br/>
                *italic* **bold** ``inline code`` escape:`*`
            </div>
            <div class="round1"></div>
            <div class="round2"></div>
            <div class="round4"></div>
        </div>
        <div style="float:right">
            <button  onclick="window.location='./input/'">show the raw input</button>
        </div>
    </td><td valign="top">
        <div style="float:left">
            <button onclick="window.location='./output/'">show the result</button>
        </div>
    </td>
    </tr></tbody></table>

<script type="text/javascript">
    var contentbox = document.getElementById("contentbox");
    contentbox.focus();
    if(contentbox.addEventListener ) {
        contentbox.addEventListener('keydown',this.keyHandler,false);
    } else if(contentbox.attachEvent ) {
        contentbox.attachEvent('onkeydown',this.keyHandler); /* damn IE hack */
    }

    var onchange_timer = null;
    function keyHandler(e) {
        if(onchange_timer)
            clearTimeout(onchange_timer);
        onchange_timer = setTimeout(send_message, 250);

        var TABKEY = 9;
        if(e.keyCode == TABKEY) {
            setTimeout(function(){
                var sc = contentbox.scrollTop;
                var caret = getCaretPosition(contentbox);
                var val = contentbox.value.substr(0, caret);
                var i = val.lastIndexOf('\n');
                var v = '    ';
                switch((val.length - i - 1) % 4){
                case 1:
                    v = '   ';
                    break;
                case 2:
                    v = '  ';
                    break;
                case 3:
                    v = ' ';
                    break;
                }
                insertAtCaret(contentbox, v);
                contentbox.scrollTop = sc;
            },0)
            if(e.preventDefault) {
                e.preventDefault();
            }
            return false;
        }
    }
</script>



    <div style="visibility:hidden;">
    <textarea id="originalbox" style="visibility:hidden;">{{contentbox}}</textarea>
    </div>

<a href="http://evserver.googlecode.com/svn/cometdemo/">This stuff is an open source!</a>











<script type="text/javascript">
    /******************** NAME STUFF ********************/
    var name= '{{name}}';
    if(Get_Cookie('name')){
        name = Get_Cookie('name');
    }else{
        Set_Cookie('name', name, 30, '/', '', '' );
    }
    var usernamebox = document.getElementById("username");
    usernamebox.innerHTML = name;

    if(usernamebox.addEventListener ) {
        usernamebox.addEventListener('keydown',usernameKeyHandler,false);
    } else if(usernamebox.attachEvent ) {
        usernamebox.attachEvent('onkeydown',usernameKeyHandler); /* damn IE hack */
    }
    $("#username").keypress(function(e){ return e.which != 13; });
    function usernameKeyHandler(e) {
        if(e.keyCode == 9 || e.which == 13 || e.keyCode == 13) {
            if(usernamebox.innerHTML != name){
                name = usernamebox.innerHTML;
                usernamebox.innerHTML = name;
                Set_Cookie('name', name, 30, '/', '', '' );
                gc();
                gc = comet_connection(url, user_callback);
            }
            setTimeout(contentbox.focus, 1);
            return false;
        }
        return true;
    }


    /******************** INFOBOX MESSAGE STUFF ********************/
    var infobox = document.getElementById("infobox");
    var info_timer = null;
    function info(msg){
        if(info_timer)
            clearTimeout(info_timer);
        infobox.innerHTML = '' + msg;
        info_timer = setTimeout(function (){
            infobox.innerHTML = '&nbsp;';
            info_timer = null;
        }, 10000);
    }
    var versionbox = document.getElementById("versionbox");
    function setversionbox(msg){
        versionbox.innerHTML = '' + msg;
    }

    /******************** HIGH LEVEL MESSAGE STUFF ********************/
    var not_often_than = 400; // sleep for XXX ms between messages
    var waiting = false;
    var outputbox = document.getElementById("outputbox");
    var usersbox = document.getElementById("users");
    var output = '';

    function send_message(){
        if(waiting)
            return;
        var payload = null;

        var v = contentbox.value.replace(/\r/g, "");
        if(original_value != v){ // different
            payload = patch_prepare(v);
        }else{ // the same
            return;
        }

        ping_set();
        if(waiting == true)
            info('bad wait!');
        waiting = true;

        send_ajax(payload, function(response){
            if(response != '0'){
                info('Some of your changes are not commited yet.');
            }
        });
    }


    function recv_message(payload){
        var a = JSON.parse(payload);
        var number = a[0];
        var over = a[1];
        var nver = a[2];
        var data = a[3];
        if(number == 'userlist'){
            usersbox.innerHTML = data;
        }else if(number != 'output'){
            patch_apply(number, data);
            if(version != over){
                info('bad version: ' + version + ' over:' + over + ' nver:' +nver);
            }

            version = nver;
            setversionbox(nver);

            if(number == patch_number){ // my message
                ping_got();
                setTimeout(function(){
                    if(waiting != true)
                        info('bad wait! ' + waiting);
                    waiting = false;
                    send_message();
                }, not_often_than);
            }
        }else{ // data
            if(nver == ''){
                output=data;

                set_iframe_document(outputbox, output);
            }else{// diff
                var i;
                var patches = dmp.patch_fromText(data);
                var a = dmp.patch_apply(patches, output);
                for(i=0; i<a[1].length; i++)
                    if(!a[1][i]){
                        info('Fatal error! Failed to patch the output!\n Please RELOAD page!\n ' + patches[i]);
                        break;
                    }
                output = a[0];
                set_iframe_document(outputbox, output);
            }
        }
    }

    /******************** PATCH STUFF ********************/
    var dmp = new diff_match_patch();
    var patch_number = null;
    var contentbox = document.getElementById('contentbox');
    var original_value = document.getElementById('originalbox').value;
    original_value = original_value.replace(/\r/g, "");

    function patch_prepare(v){
        var diffs = dmp.diff_main(original_value, v);
        dmp.diff_cleanupEfficiency(diffs);
        var payload = dmp.patch_toText(dmp.patch_make(diffs));
        if(!payload || payload.length == 0){
            info('Content should be different but is the same');
            return;
        }
        patch_number = (''+Math.random()).substr(2, 6);
        return JSON.stringify([patch_number, version, '-1', payload]);;
    }

    function patch_apply(number, payload){
        var i;
        var patches = dmp.patch_fromText(payload);
        var a = dmp.patch_apply(patches, original_value);
        for(i=0; i<a[1].length; i++)
            if(!a[1][i]){
                info('Fatal error! Failed to patch the primary copy of server data!\n Please RELOAD page!\n ' + patches[i]);
                break;
            }

        original_value = a[0];

        if(number == patch_number) // my message, don't apply
            return true;


        var a = dmp.patch_apply(patches, contentbox.value.replace(/\r/g, ""));
        for(i=0; i<a[1].length; i++)
            if(!a[1][i]){
                info("Conflict detected. Some of your chages could stay, some could be overwritten.");
                break
            }

        var new_content = a[0];

        var cursor = saveCursor(dmp, contentbox);
        contentbox.value = new_content;
        restoreCursor(dmp, contentbox, cursor);
        return true;
    }


    /******************** PING STUFF ********************/
    var rtt = new Rfc2988();
    function ping_set(){
        rtt.t0 = (new Date()).getTime()/1000.0;
    }
    function ping_got(){
        var now = (new Date()).getTime()/1000.0;
        rtt.update((now - rtt.t0) * 1000.0);
        document.getElementById("latency").innerHTML = '' + (rtt.get()/2.0).toFixed(0) + 'ms';
    }


    /******************** AJAX/COMET STUFF ********************/
    var version={{contentversion}};

    function send_ajax(payload, callback){
        var payload = payload;
        var xhr;
        var ors = function(){
            if(!xhr) return;
            if(xhr.readyState==4){
                var response = xhr.responseText;
                if(xhr.status!=200){
                    info('Fatal ajax error, retrying in few seconds. Payload: ' + payload);
                    setTimeout(function(){
                        xhr = comet_create_ajax('./push/', 'POST', payload, ors);
                    }, 8000);
                    return;
                }
                try{
                    xhr.abort();
                }catch(e){};
                delete(xhr);
                xhr = null;
                callback(response)
            }
        }
        xhr = comet_create_ajax('./push/', 'POST', payload, ors);
    }

    function user_callback(data){
        if(data=="ping") // keepalive from server
            return;
        if(data=="refresh"){
            window.location.reload();
            return;
        }
        if(!data || data.length==0)
            return;
        recv_message(data);
    }

    function url(){
        return "./pop/?v=" + version +'&n='+name+'&a=' + (''+Math.random()).substr(2,6);
    }


    var gc = comet_connection(url, user_callback);

    info("Start editing right now!");
</script>


</body>
</html>










